package cc.linker.steplink.crm.commons.service;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Encoder;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

@Slf4j
@Service
public class CommonsService {

    @Value("${express.appcode}")
    private String expressAppcode;


    private String globalLimitScript =
            "local key_local = redis.call('setnx',KEYS[1],0)\n" +
                    "if tonumber(key_local) == 0 then\n" +
                    "    if tonumber(redis.call('get',KEYS[1]))>=tonumber(ARGV[2]) then\n" +
                    "        return false\n" +
                    "    else\n" +
                    "        redis.call('incr',KEYS[1])\n" +
                    "        return true\n" +
                    "    end\n" +
                    "else\n" +
                    "    redis.call('incr',KEYS[1])\n" +
                    "    redis.call('pexpire',KEYS[1],ARGV[1])\n" +
                    "    return true\n" +
                    "end";
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 针对某个key使用lua脚本进行限流
     * 使用lua优点，可以保证多个命令是一次行传输到Redis服务器并且是串行执行的，保证串行执行的命令中不行插入其他命令，防止并发问题
     * 步骤：
     * 1、判断key是否存在，如果不存在，保存该key，设置值为1，设置多少毫秒（n）最多进行几次（m)
     * 2、如果值存在，先判断key是否超时了，如果超时则删除，并重新执行步骤1，如果key未超时，则判断是否超过n毫秒最多m次的限制
     *
     * @param key
     */
    public Boolean getGlobalLimitByLua(String key, int mlitimes, int maxCount) {
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(globalLimitScript,Boolean.class);
        return stringRedisTemplate.execute(redisScript, Collections.singletonList(key), String.valueOf(mlitimes), String.valueOf(maxCount));
    }


    /**
     * 获取物流信息
     * @param expressNo 快递单号
     * @return {"status":"0","msg":"ok","result":""}
     * "status":"0" 正常，"status":"1" 异常
     * "msg" 请求信息
     */
    public Map<String,Object> getExpressList(String expressNo){
        if(StringUtils.isEmpty(expressNo)){
            return new HashMap<>();
        }
        String host = "https://wuliu.market.alicloudapi.com";// 【1】请求地址 支持http 和 https 及 WEBSOCKET
        String path = "/kdi";  // 【2】后缀
        String appcode = expressAppcode; // 【3】开通服务后 买家中心-查看AppCode
        String type = ""; //  【4】请求参数，不知道可不填 95%能自动识别
        String urlSend = host + path + "?no=" + expressNo +"&type="+type;  // 【5】拼接请求链接
        try {
            URL url = new URL(urlSend);
            HttpURLConnection httpURLCon = (HttpURLConnection) url.openConnection();
            httpURLCon .setRequestProperty("Authorization", "APPCODE " + appcode);// 格式Authorization:APPCODE (中间是英文空格)
            int httpCode = httpURLCon.getResponseCode();
            if (httpCode == 200) {
                StringBuilder sb = new StringBuilder();
                BufferedReader br = new BufferedReader(new InputStreamReader(httpURLCon.getInputStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    line = new String(line.getBytes(), StandardCharsets.UTF_8);
                    sb.append(line);
                }
                br.close();
                return (Map) JSON.parse(sb.toString());
            } else {
                Map<String, List<String>> map = httpURLCon.getHeaderFields();
                String error = map.get("X-Ca-Error-Message").get(0);
                Map<String,Object> data = new HashMap<>();
                data.put("status","1");
                data.put("msg",error);
                return data;
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        Map<String,Object> data = new HashMap<>();
        data.put("status","1");
        data.put("msg","系统繁忙，请稍后再试");
        return data;
    }

    /**
     * @param list     数据
     * @param key      与标题对应
     * @param title    标题
     * @param fileName 文件名
     * @param response
     * @throws Exception
     */
    public void excelDownload(List<Map<String, Object>> list, String[] key, String[] title, String fileName, HttpServletResponse response) throws Exception {
        String sheetName = "sheet1";
        fileName += ".xls";
        String[][] str = new String[list.size()][title.length];
        int i = 0;
        for (String[] strings : str) {
            Map<String, Object> map = list.get(i);
            int j = 0;
            for (String s : key) {
                Object o = map.get(s);
                if (o != null) {
                    strings[j] = o.toString();
                }
                j++;
            }
            i++;
        }
        HSSFWorkbook wb = new HSSFWorkbook();
        wb = getHSSFWorkbook(sheetName, title, str, wb);

        //生成excel文件
//        buildExcelFile(fileName, wb);
        //浏览器下载excel
        buildExcelDocument(fileName, wb, response);
//        return "download excel";
    }

    public void exportTemplate(List<Map<String, Object>> list, String[] key, String[] title, String fileName, HttpServletResponse response) throws Exception {
        String sheetName = "sheet1";
        fileName += ".xls";
        String[][] str = new String[list.size()][title.length];
        int i = 0;
        for (String[] strings : str) {
            Map<String, Object> map = list.get(i);
            int j = 0;
            for (String s : key) {
                Object o = map.get(s);
                if (o != null) {
                    strings[j] = o.toString();
                }
                j++;
            }
            i++;
        }
        HSSFWorkbook wb = new HSSFWorkbook();
        wb = getHSSFWorkbookCustomerTemplate(sheetName, title, str, wb);

        //生成excel文件
//        buildExcelFile(fileName, wb);
        //浏览器下载excel
        buildExcelDocument(fileName, wb, response);
//        return "download excel";
    }



    //生成excel文件
    private void buildExcelFile(String filename, HSSFWorkbook workbook) throws Exception {
        FileOutputStream fos = new FileOutputStream(filename);
        workbook.write(fos);
        fos.flush();
        fos.close();
    }

    //浏览器下载excel
    private void buildExcelDocument(String filename, HSSFWorkbook workbook, HttpServletResponse response) throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));
        OutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
        outputStream.flush();
        outputStream.close();
    }

    /**
     * 导出Excel
     *
     * @param sheetName sheet名称
     * @param title     标题
     * @param values    内容
     * @param wb        HSSFWorkbook对象
     * @return
     */
    private static HSSFWorkbook getHSSFWorkbook(String sheetName, String[] title, String[][] values, HSSFWorkbook wb) {

        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        if (wb == null) {
            wb = new HSSFWorkbook();
        }
        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);
        for (int i = 0; i < 32; i++) {
            sheet.setColumnWidth(i, 256 * 20 + 184);
        }
        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        HSSFRow row = sheet.createRow(0);
        // 第四步，创建单元格，并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        // 创建一个居中格式
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        HSSFFont font = wb.createFont();
        font.setFontName("黑体");
        //设置字体大小
        font.setFontHeightInPoints((short) 14);
        style.setFont(font);
        //声明列对象
        HSSFCell cell = null;
        //创建标题
        for (int i = 0; i < title.length; i++) {
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(style);
        }
        //创建内容
        for (int i = 0; i < values.length; i++) {
            row = sheet.createRow(i + 1);
            for (int j = 0; j < values[i].length; j++) {
                //将内容按顺序赋给对应的列对象
                cell = row.createCell(j);
                if (values[i][j] == null || "".equals(values[i][j])) {
                    continue;
                } else {
                    cell.setCellValue(values[i][j]);
                }
            }
        }
        return wb;
    }

    private static HSSFWorkbook getHSSFWorkbookCustomerTemplate(String sheetName, String[] title, String[][] values, HSSFWorkbook wb) {

        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        if (wb == null) {
            wb = new HSSFWorkbook();
        }
        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);
        for (int i = 0; i < 32; i++) {
            sheet.setColumnWidth(i, 256 * 20 + 184);
        }
        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        HSSFRow row = sheet.createRow(0);
        // 第四步，创建单元格，并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        HSSFCellStyle style2 = wb.createCellStyle();
        HSSFFont font2 = wb.createFont();
        font2.setColor(HSSFColor.GREY_25_PERCENT.index);
        style2.setFont(font2);
        // 创建一个居中格式
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        HSSFFont font = wb.createFont();
        font.setFontName("黑体");

        //设置字体大小
        font.setFontHeightInPoints((short) 14);
        style.setFont(font);
        //声明列对象
        HSSFCell cell = null;
        //创建标题
        for (int i = 0; i < title.length; i++) {
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(style);
        }

        //创建内容
        for (int i = 0; i < values.length; i++) {
            row = sheet.createRow(i + 1);
            for (int j = 0; j < values[i].length; j++) {
                //将内容按顺序赋给对应的列对象
                cell = row.createCell(j);
                if (values[i][j] == null || "".equals(values[i][j])) {
                    continue;
                } else {
                    cell.setCellStyle(style2);
                    cell.setCellValue(values[i][j]);
                }
            }
        }
        return wb;
    }


    public String encodeImageToBase64(String imgFilePath){
        HttpURLConnection conn;
        try {
            conn = (HttpURLConnection) new URL(imgFilePath).openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5 * 1000);
            InputStream inStream = conn.getInputStream();
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
            }
            inStream.close();
            byte[] data = outStream.toByteArray();
            BASE64Encoder encoder = new BASE64Encoder();
            return "data:image/jpeg;base64,"+ encoder.encode(data);//返回Base64编码过的字节数组字符串
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error("图片转base64失败",imgFilePath);
        }
        return "";
    }

    public static String getImageStr(String imgPath) {// 将图片文件转化为字节数组字符串，并对其进行Base64编码处理
        String imgFile = imgPath;// 待处理的图片
        InputStream in = null;
        byte[] data = null;
        String encode = null; // 返回Base64编码过的字节数组字符串
        // 对字节数组Base64编码
        BASE64Encoder encoder = new BASE64Encoder();
        try {
            // 读取图片字节数组
            in = new FileInputStream(imgFile);
            data = new byte[in.available()];
            in.read(data);
            encode = encoder.encode(data);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return encode;
    }
}
